package service

import (
	"context"
	"fmt"
	"github.com/pkg/errors"
	"gorm.io/gorm"
	"pay/api/pay"
	"pay/internal/constant"
	"pay/internal/model"
	"pay/pkg/ecode"
)

// 查看支付宝收款账户配置
func (s *Service) GetAlipayAccountList(ctx context.Context, req *pay.CommonPaginateRequest) (
	resp *pay.GetAlipayAccountListResp, err error) {
	if err = s.downstream.CheckPermissionByRoute(ctx, req.Token, 0, "alipay"); err != nil {
		return
	}
	var configs []*model.AlipayConfigQueryModel
	resp = &pay.GetAlipayAccountListResp{}
	if configs, resp.Total, err = s.dao.FindAlipayConfigsByPage(
		ctx, req.Token.SgId, req.PStoreId, req.PageNo, req.PageSize); err != nil {
		return
	}
	for _, config := range configs {
		resp.Accounts = append(resp.Accounts, &pay.AlipayAccountView{
			Id:     config.ID,
			Name:   config.Name,
			AppId:  config.AppId,
			PId:    config.Pid,
			Status: pay.AlipayAccountStatus(config.AccountStatus),
		})
	}
	return
}

// 获取支付宝当面付授权链接(授权成功自动查询进件状态)
func (s *Service) AuthAlipay(ctx context.Context, req *pay.CommonRequest) (
	resp *pay.AlipayAuthResp, err error) {
	if err = s.downstream.CheckPermissionByRoute(ctx, req.Token, 0, "alipay"); err != nil {
		return
	}
	resp = &pay.AlipayAuthResp{AppId: model.BootInfo.AlipayServiceProviderAppId}
	return
}

// 编辑支付宝收款账户别名
func (s *Service) EditAlipayAccount(ctx context.Context, req *pay.EditAlipayAccountRequest) (
	resp *pay.DefaultResp, err error) {
	if err = s.downstream.CheckPermissionByRoute(ctx, req.Token, 0, "alipay"); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		config := &model.AlipayConfig{}
		if err = s.dao.LockObjectByID(ctx, config, req.Id, req.Token.SgId, req.PStoreId); err != nil {
			if errors.Cause(err) == gorm.ErrRecordNotFound {
				err = constant.ErrObjectNotExist
				return
			}
			return
		}
		config.Name = req.Name
		config.Operator = req.Token.EmpId
		if err = s.dao.Save(ctx, config); err != nil {
			return
		}
		return
	}); err != nil {
		return
	}
	resp = &pay.DefaultResp{Status: true}
	return
}

// 删除支付宝收款账户
func (s *Service) DeleteAlipayAccount(ctx context.Context, req *pay.CommonObjectRequest) (
	resp *pay.DefaultResp, err error) {
	if err = s.downstream.CheckPermissionByRoute(ctx, req.Token, 0, "alipay"); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		config := &model.AlipayConfig{}
		if err = s.dao.LockObjectByID(ctx, config, req.Id, req.Token.SgId, req.PStoreId); err != nil {
			if errors.Cause(err) == gorm.ErrRecordNotFound {
				err = constant.ErrObjectNotExist
				return
			}
			return
		}
		var storeConfigs []*model.StoreConfig
		if storeConfigs, err = s.dao.FindStoreConfigsByAccountId(
			ctx, req.Id, req.Token.SgId, req.PStoreId, pay.PayType_PAY_ALIPAY); err != nil {
			return
		}
		if len(storeConfigs) != 0 {
			err = ecode.AppendMessage(constant.ErrForbiddenAction, "有门店正在使用该收款账户，请先解绑再删除")
			return
		}
		config.Status = false
		config.Operator = req.Token.EmpId
		if err = s.dao.Save(ctx, config); err != nil {
			return
		}
		// 没有人使用的授权，自动置为停用，不再触发刷新任务
		if s.dao.CanAlipayTokenDisabled(ctx, config.TokenId) {
			if err = s.dao.DisableAlipayToken(ctx, config.TokenId); err != nil {
				return
			}
			return
		}
		return
	}); err != nil {
		return
	}
	resp = &pay.DefaultResp{Status: true}
	return
}

// 创建支付宝进件申请单并提交进件 / 基于已有申请重新发起进件
func (s *Service) ApplyAlipayAccount(ctx context.Context, req *pay.ApplyAlipayAccountRequest) (
	resp *pay.ApplyAlipayAccountResp, err error) {
	if err = s.downstream.CheckPermissionByRoute(ctx, req.Token, 0, "alipay"); err != nil {
		return
	}
	var reSubmit bool
	config := &model.AlipayConfig{}
	tokenConfig := &model.AlipayToken{}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		if err = s.dao.LockObjectByID(ctx, config, req.Id, req.Token.SgId, req.PStoreId); err != nil {
			if errors.Cause(err) == gorm.ErrRecordNotFound {
				err = constant.ErrObjectNotExist
				return
			}
			return
		}
		if err = s.dao.LockAlipayTokenByID(ctx, tokenConfig, config.TokenId); err != nil {
			if errors.Cause(err) == gorm.ErrRecordNotFound {
				err = constant.ErrObjectNotExist
				return
			}
			return
		}
		switch pay.AlipayAccountStatus(tokenConfig.AccountStatus) {
		case pay.AlipayAccountStatus_valid, pay.AlipayAccountStatus_restrictValid:
			err = ecode.AppendMessage(constant.ErrForbiddenAction, "账户已经进件完成，不需要重复申请")
			return
		case pay.AlipayAccountStatus_auditReject, pay.AlipayAccountStatus_invalid, pay.AlipayAccountStatus_restrictInvalid:
			reSubmit = true
			fallthrough
		case pay.AlipayAccountStatus_ALIPAY_STATUS_INIT, pay.AlipayAccountStatus_none:
			// 重新发起进件
			tokenConfig.AccountStatus = uint8(pay.AlipayAccountStatus_ALIPAY_STATUS_INIT)
			config.Operator = req.Token.EmpId
			if err = s.dao.Save(ctx, config); err != nil {
				return
			}

		default:
			err = ecode.AppendMessage(constant.ErrForbiddenAction, "账户进件流程进行中，不允许重新发起申请")
			return
		}
		resp = &pay.ApplyAlipayAccountResp{}
		if resp.ApplyResult, err = s.downstream.AlipayApply(ctx, req, tokenConfig, reSubmit); err != nil {
			return
		}
		tokenConfig.ApplyNo = resp.ApplyResult.ApplyNo
		tokenConfig.AccountStatus = uint8(pay.AlipayAccountStatus_audit)
		if err = s.dao.Save(ctx, tokenConfig); err != nil {
			return
		}
		return
	}); err != nil {
		return
	}
	resp.AccountInfo = &pay.AlipayAccountView{
		Id:     config.ID,
		Name:   config.Name,
		AppId:  tokenConfig.AppId,
		PId:    tokenConfig.UserId,
		Status: pay.AlipayAccountStatus(tokenConfig.AccountStatus),
	}
	return
}

// 查看支付宝进件详细信息（基于收款账户ID）
func (s *Service) QueryAlipayAccountApply(ctx context.Context, req *pay.CommonObjectRequest) (
	resp *pay.QueryAlipayAccountApplyResp, err error) {
	if err = s.downstream.CheckPermissionByRoute(ctx, req.Token, 0, "alipay"); err != nil {
		return
	}
	config := &model.AlipayConfig{}
	tokenConfig := &model.AlipayToken{}
	resp = &pay.QueryAlipayAccountApplyResp{}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		if err = s.dao.LockObjectByID(ctx, config, req.Id, req.Token.SgId, req.PStoreId); err != nil {
			if errors.Cause(err) == gorm.ErrRecordNotFound {
				err = constant.ErrObjectNotExist
				return
			}
			return
		} else if !config.Status {
			err = constant.ErrObjectNotExist
			return
		}
		if err = s.dao.LockAlipayTokenByID(ctx, tokenConfig, config.TokenId); err != nil {
			if errors.Cause(err) == gorm.ErrRecordNotFound {
				err = constant.ErrObjectNotExist
				return
			}
			return
		}
		if tokenConfig.ApplyNo == "" {
			err = ecode.AppendMessage(constant.ErrNeedRefresh, "尚未发起进件，不能查询")
			return
		}

		if resp.QueryResult, err = s.downstream.QueryAlipayApply(
			ctx, tokenConfig, req.Token.SgId); err != nil {
			return
		}
		// 需要触发同步
		if applyStatus, ok := pay.AlipayApplyStatus_value[resp.QueryResult.ApplyState]; ok {
			var targetStatus pay.AlipayAccountStatus
			switch pay.AlipayApplyStatus(applyStatus) {
			case pay.AlipayApplyStatus_MERCHANT_INFO_HOLD:
				targetStatus = pay.AlipayAccountStatus_none
			case pay.AlipayApplyStatus_MERCHANT_AUDITING:
				targetStatus = pay.AlipayAccountStatus_audit
			case pay.AlipayApplyStatus_MERCHANT_CONFIRM:
				targetStatus = pay.AlipayAccountStatus_waitConfirm
			case pay.AlipayApplyStatus_MERCHANT_CONFIRM_SUCCESS:
				targetStatus = pay.AlipayAccountStatus_valid
			case pay.AlipayApplyStatus_MERCHANT_CONFIRM_TIME_OUT, pay.AlipayApplyStatus_MERCHANT_APPLY_ORDER_CANCELED:
				targetStatus = pay.AlipayAccountStatus_auditReject
			}
			if targetStatus != pay.AlipayAccountStatus(tokenConfig.AccountStatus) {
				tokenConfig.AccountStatus = uint8(targetStatus)
				if err = s.dao.Save(ctx, tokenConfig); err != nil {
					return
				}
			}
		} else {
			err = fmt.Errorf("支付宝进件申请新增了未对接状态：%s", resp.QueryResult.ApplyState)
		}
		return
	}); err != nil {
		return
	}
	resp.AccountInfo = &pay.AlipayAccountView{
		Id:     config.ID,
		Name:   config.Name,
		AppId:  tokenConfig.AppId,
		PId:    tokenConfig.UserId,
		Status: pay.AlipayAccountStatus(tokenConfig.AccountStatus),
	}
	return
}
